﻿using System;
using System.Collections.Generic;
using System.Text;
using llAma.Interface;
using llAma.Backend.Interface;
using llAma.Base;
using Reflector;
using dAmn;
using System.Reflection;
using llamaServer;

namespace llAma.Base
{
    [Flags]
    public enum PropertyHandlerMask : int
    {
        GETTER = 1, SETTER = 2
    }
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
    public class PropertyHandlerAttribute : Attribute
    {
        private string mName;
        private PropertyHandlerMask mActions;

        public PropertyHandlerAttribute(string propertyName, PropertyHandlerMask propertymethodtype)
        {
            this.Name = propertyName;
            this.Actions = propertymethodtype;
        }

        public string Name
        {
            get
            {
                return this.mName;
            }
            private set
            {
                this.mName = value;
            }
        }

        public PropertyHandlerMask Actions
        {
            get
            {
                return this.mActions;
            }
            private set
            {
                this.mActions = value;
            }
        }
    }
    public class PropertyManagerBase : llamaCommonBase, IPropertyManager
    {
        private string mNamespace;
        Dictionary<string, List<MethodAndAttribute<PropertyHandlerAttribute>>> handlers = new Dictionary<string, List<MethodAndAttribute<PropertyHandlerAttribute>>>();
        protected PropertyManagerBase()
        {

        }
        private bool setupDone = false;
        private void doSetupIfRequired()
        {
            lock (handlers)
            {
                if (!setupDone)
                {
                    foreach (MethodAndAttribute<PropertyHandlerAttribute> maa in Reflector<PropertyHandlerAttribute>.Search(this, methodPredicateMatcher))
                    {
                        if (!handlers.ContainsKey(maa.Attribute.Name)) handlers[maa.Attribute.Name] = new List<MethodAndAttribute<PropertyHandlerAttribute>>();
                        handlers[maa.Attribute.Name].Add(maa);
                    }
                }
                setupDone = true;
            }
        }
        private bool methodPredicateMatcher(MethodInfo mi)
        {
            ParameterInfo[] methodParameters = mi.GetParameters();
            if (methodParameters.Length != 3) return false;
            if (methodParameters[0].ParameterType != typeof(Packet)) return false;
            if (methodParameters[1].ParameterType != typeof(object)) return false;
            if (methodParameters[2].ParameterType != typeof(PropertyHandlerMask)) return false;
            return true;
        }
        private void handleGetSetEvent(string property, Packet p, object sender, PropertyHandlerMask mask)
        {
            doSetupIfRequired();
            List<MethodAndAttribute<PropertyHandlerAttribute>> exec = new List<MethodAndAttribute<PropertyHandlerAttribute>>();
            if (handlers.ContainsKey(property)) exec.AddRange(handlers[property]);
            for (int x = 0; x < exec.Count; x++)
            {
                if ((exec[x].Attribute.Actions & mask) == mask)
                {
                    try 
                    { 
                        exec[x].Invoke(p, sender, mask);
                    }
                    catch { }
                }
            }
        }
        string IPropertyManager.Namespace
        {
            get { return this.mNamespace; }
        }
        public string Namespace
        {
            get { return mNamespace; }
            protected set { mNamespace = value; }
        }
        [PacketHandler("get")]
        [PacketHandler("set")]
        protected void handleGetSetPackets(Packet p, IConnection conn)
        {
            //This is not intended for us.
            if (p.param.ToLower().Trim() != this.Namespace.ToLower().Trim())
                return;
            if (!conn.CurrentUser.SecurityCheck(p))
                return;
            if (!p.args.ContainsKey("p"))
            {
                SendErrorPacketToClient(conn, p, "bad request");
                return;
            }
            PropertyHandlerMask mask = PropertyHandlerMask.GETTER;
            if (p.cmd.ToLower().Trim() == "set")
                mask = PropertyHandlerMask.SETTER;
            this.handleGetSetEvent(p.args["p"], p, conn, mask);
        }

        protected override string GetNamespace()
        {
            return this.Namespace;
        }
    }
}
